package com.hqq.concurrency.reactor.example;

import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.util.Iterator;
import java.util.Set;

/**
 * Reactor
 * Created by heqianqian on 2017/8/5.
 */
public class Reactor implements Runnable {

    public final Selector selector;

    public final ServerSocketChannel serverSocketChannel;

    public Reactor(int port) throws IOException {
        //初始化选择器
        selector = Selector.open();
        //初始化socket通道
        serverSocketChannel = ServerSocketChannel.open();
        //设置网络地址
        InetSocketAddress inetSocketAddress = new InetSocketAddress(InetAddress.getLocalHost(), port);
        //将socket的监听绑定到该地址上
        serverSocketChannel.socket().bind(inetSocketAddress);
        //设置为非阻塞模式
        serverSocketChannel.configureBlocking(false);
        //注册selector 并且返回SelectionKey
        SelectionKey selectionKey = serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
        //利用selectionKey的attach功能绑定Acceptor 如果有事情，触发Acceptor
        selectionKey.attach(new Accepter(this));
    }

    @Override
    public void run() {
        try {
            while (!Thread.interrupted()) {
                selector.select();
                Set<SelectionKey> selectionKeys = selector.selectedKeys();
                Iterator<SelectionKey> iterator = selectionKeys.iterator();
                while (iterator.hasNext()) {
                    SelectionKey selectionKey = iterator.next();
                    dispatch(selectionKey);
                }
                selectionKeys.clear();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 运行Acceptor或SocketReadHandler
     */
    private void dispatch(SelectionKey selectionKey) {
        Runnable runnable = (Runnable) selectionKey.attachment();
        if (runnable != null) {
            runnable.run();
        }
    }
}
